from PyQt5.QtCore import QThread, pyqtSignal
from msal import PublicClientApplication
import requests
import webbrowser
import threading
from http.server import HTTPServer, BaseHTTPRequestHandler
from urllib.parse import parse_qs, urlparse
import csv
import pandas as pd
from common.logOutput import info, error, class_email_send_decoration

# 自定义 HTTP 请求处理器，用于捕获授权码
class OAuthHandler(BaseHTTPRequestHandler):
    def do_GET(self):
        # 解析重定向 URL 中的查询参数
        query = parse_qs(urlparse(self.path).query)
        if "code" in query:
            self.server.auth_code = query["code"][0]
            self.send_response(200)
            self.send_header("Content-type", "text/html")
            self.end_headers()
            self.wfile.write(b"success")
        else:
            self.send_response(400)
            self.end_headers()

@class_email_send_decoration
class AuthManager:
    def __init__(self, client_id: str, tenant_id: str):
        self.client_id = client_id
        self.tenant_id = tenant_id
        self.authority = f"https://login.microsoftonline.com/{tenant_id}"
        self.redirect_uri = "http://localhost:8080"  # 与 Azure 配置一致
        self.scopes = ["User.Read", "Mail.Send", "Files.ReadWrite"]  # 仅使用需要的权限

        self.app = PublicClientApplication(
            client_id=client_id,
            authority=self.authority,
        )
        self.access_token = None
        self.refresh_token = None

    def login(self) -> bool:
        """交互式登录：打开浏览器登录，获取授权码并换取 token"""
        # 获取授权 URL
        auth_url = self.app.get_authorization_request_url(
            self.scopes,
            redirect_uri=self.redirect_uri,
        )

        # 启动本地 HTTP 服务器监听重定向
        server = HTTPServer(("localhost", 8080), OAuthHandler)
        server.auth_code = None
        server_thread = threading.Thread(target=server.serve_forever)
        server_thread.daemon = True
        server_thread.start()

        # 打开浏览器进行登录
        info("正在打开浏览器，请登录 Microsoft 账户...")
        webbrowser.open(auth_url)

        # 等待授权码
        while server.auth_code is None:
            pass

        # 获取授权码
        auth_code = server.auth_code
        info(f"获取到授权码: {auth_code[:10]}...")

        # 关闭服务器
        server.shutdown()

        # 使用授权码换取 token
        result = self.app.acquire_token_by_authorization_code(
            auth_code,
            scopes=self.scopes,
            redirect_uri=self.redirect_uri,
        )

        if "access_token" in result:
            self.access_token = result["access_token"]
            self.refresh_token = result.get("refresh_token")
            info(f"成功获取 token: {self.access_token[:10]}...")
            return True
        else:
            error(f"登录失败: {result.get('error_description')}")
            return False

    def refresh_access_token(self) -> bool:
        """刷新 token（如果有 refresh_token）"""
        if not self.refresh_token:
            error("没有可用的 refresh token")
            return False

        result = self.app.acquire_token_by_refresh_token(
            self.refresh_token,
            scopes=self.scopes,
        )

        if "access_token" in result:
            self.access_token = result["access_token"]
            self.refresh_token = result.get("refresh_token")
            info("Token 已刷新")
            return True
        else:
            error(f"刷新 token 失败: {result.get('error_description')}")
            return False

# 邮件发送线程，用于批量发送邮件
class EmailSender(QThread):
    log_signal = pyqtSignal(str)  # 日志信号
    progress_signal = pyqtSignal(int)  # 进度信号

    def __init__(self, auth_manager: AuthManager, sender_email: str, recipients: list, subject: str, body: str, attachment_path: str = None, count: int = 1):
        super().__init__()
        self.auth_manager = auth_manager
        self.sender_email = sender_email
        self.recipients = recipients
        self.subject = subject
        self.body = body
        self.attachment_path = attachment_path
        self.count = count  # 发送数量

    def run(self):
        total_emails = len(self.recipients) * self.count  # 总邮件数（根据发送数量重复）
        sent_count = 0

        for _ in range(self.count):  # 根据发送数量重复发送
            for i, recipient in enumerate(self.recipients, 1):
                if not self.auth_manager.access_token:
                    self.log_signal.emit("未登录，请先登录 M365")
                    return

                success = self.send_email(recipient)
                if success:
                    self.log_signal.emit(f"邮件发送成功: {recipient}")
                else:
                    self.log_signal.emit(f"邮件发送失败: {recipient}")
                sent_count += 1
                progress = int((sent_count / total_emails) * 100)
                self.progress_signal.emit(progress)

    def send_email(self, recipient: str) -> bool:
        url = "https://graph.microsoft.com/v1.0/me/sendMail"
        headers = {
            "Authorization": f"Bearer {self.auth_manager.access_token}",
            "Content-Type": "application/json",
        }
        payload = {
            "message": {
                "subject": self.subject,
                "body": {
                    "contentType": "Text",
                    "content": self.body,
                },
                "toRecipients": [
                    {"emailAddress": {"address": recipient}}
                ],
                "from": {"emailAddress": {"address": self.sender_email}},
            },
            "saveToSentItems": "true",
        }

        # 如果有附件，需扩展此逻辑（当前仅支持文本邮件）
        response = requests.post(url, headers=headers, json=payload)
        if response.status_code == 202:
            return True
        else:
            error(f"发送失败: {response.text}")
            # 如果是 token 过期，尝试刷新
            if response.status_code == 401:
                if self.auth_manager.refresh_access_token():
                    headers["Authorization"] = f"Bearer {self.auth_manager.access_token}"
                    response = requests.post(url, headers=headers, json=payload)
                    return response.status_code == 202
            return False

# 解析收件人的辅助函数
def parse_recipients(recipient_input: str, file_path: str = None) -> list:
    """解析收件人，支持手动输入和文件读取"""
    recipients = []
    if recipient_input:
        recipients = [email.strip() for email in recipient_input.split(",") if email.strip()]
    elif file_path:
        if file_path.endswith(".csv"):
            with open(file_path, "r", encoding="utf-8") as f:
                reader = csv.reader(f)
                next(reader)  # 跳过标题行
                recipients = [row[0].strip() for row in reader if row]
        elif file_path.endswith(".xlsx"):
            df = pd.read_excel(file_path)
            recipients = df.iloc[:, 0].dropna().tolist()  # 假设邮箱在第一列
    return recipients